home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume21 / amd / part12 < prev    next >
Encoding:
Internet Message Format  |  1990-04-10  |  36.8 KB

  1. Subject:  v21i100:  An Automounter for NFS systems, Part12/13
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: 60838ad5 301504fc 75b51c90 692b9c79
  5.  
  6. Submitted-by: Jan-Simon Pendry <jsp@doc.ic.ac.uk>
  7. Posting-number: Volume 21, Issue 100
  8. Archive-name: amd/part12
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 12 (of 13)."
  17. # Contents:  afs_ops.c
  18. # Wrapped by rsalz@papaya.bbn.com on Tue Apr 10 15:12:16 1990
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. if test -f 'afs_ops.c' -a "${1}" != "-c" ; then 
  21.   echo shar: Will not clobber existing file \"'afs_ops.c'\"
  22. else
  23. echo shar: Extracting \"'afs_ops.c'\" \(34481 characters\)
  24. sed "s/^X//" >'afs_ops.c' <<'END_OF_FILE'
  25. X/*
  26. X * $Id: afs_ops.c,v 5.1.1.3 90/01/11 16:58:01 jsp Exp Locker: jsp $
  27. X *
  28. X * Copyright (c) 1990 Jan-Simon Pendry
  29. X * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
  30. X * Copyright (c) 1990 The Regents of the University of California.
  31. X * All rights reserved.
  32. X *
  33. X * This code is derived from software contributed to Berkeley by
  34. X * Jan-Simon Pendry at Imperial College, London.
  35. X *
  36. X * Redistribution and use in source and binary forms are permitted
  37. X * provided that the above copyright notice and this paragraph are
  38. X * duplicated in all such forms and that any documentation,
  39. X * advertising materials, and other materials related to such
  40. X * distribution and use acknowledge that the software was developed
  41. X * by Imperial College of Science, Technology and Medicine, London, UK.
  42. X * The names of the College and University may not be used to endorse
  43. X * or promote products derived from this software without specific
  44. X * prior written permission.
  45. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  46. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  47. X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  48. X *
  49. X *    %W% (Berkeley) %G%
  50. X */
  51. X
  52. X#include "am.h"
  53. X
  54. X#define NFS
  55. X#define NFSCLIENT
  56. X
  57. X#include <sys/stat.h>
  58. X#ifdef NFS_3
  59. Xtypedef nfs_fh fhandle_t;
  60. X#endif
  61. X#ifdef NFS_HDR
  62. X#include NFS_HDR
  63. X#endif
  64. X#include <sys/mount.h>
  65. X#include "mount.h"
  66. X
  67. X/*
  68. X * Automount file system
  69. X */
  70. X
  71. X/*
  72. X * Interval between forced retries of a mount.
  73. X */
  74. X#define RETRY_INTERVAL    2
  75. X
  76. X/*
  77. X * AFS needs nothing in particular.
  78. X */
  79. Xstatic int afs_match(fo)
  80. Xam_opts *fo;
  81. X{
  82. X    char *p = fo->opt_rfs;
  83. X    if (!fo->opt_rfs) {
  84. X        plog(XLOG_USER, "auto: no mount point named (rfs:=)");
  85. X        return 0;
  86. X    }
  87. X    if (!fo->opt_fs) {
  88. X        plog(XLOG_USER, "auto: no map named (fs:=)");
  89. X        return 0;
  90. X    }
  91. X    /*
  92. X     * Swap round fs:= and rfs:= options
  93. X     * ... historical (jsp)
  94. X     */
  95. X    fo->opt_rfs = fo->opt_fs;
  96. X    fo->opt_fs = p;
  97. X    /*
  98. X     * fs_mtab turns out to be the name of the mount map
  99. X     */
  100. X    fo->fs_mtab = strealloc(fo->fs_mtab, fo->opt_rfs ? fo->opt_rfs : ".");
  101. X    return 1;
  102. X}
  103. X
  104. Xstatic int afs_init(mf)
  105. Xmntfs *mf;
  106. X{
  107. X    /*
  108. X     * Fill in attribute fields
  109. X     */
  110. X    mf->mf_fattr.type = NFDIR;
  111. X    mf->mf_fattr.mode = NFSMODE_DIR | 0555;
  112. X    mf->mf_fattr.nlink = 2;
  113. X    mf->mf_fattr.size = 512;
  114. X
  115. X    return 0;
  116. X}
  117. X
  118. X/*
  119. X * Mount the an automounter directory.
  120. X * The automounter is connected into the system
  121. X * as a user-level NFS server.  mount_afs constructs
  122. X * the necessary NFS parameters to be given to the
  123. X * kernel so that it will talk back to us.
  124. X */
  125. Xstatic int mount_afs(dir, fs_name, opts)
  126. Xchar *dir;
  127. Xchar *fs_name;
  128. Xchar *opts;
  129. X{
  130. X    struct nfs_args nfs_args;
  131. X    struct mntent mnt;
  132. X    int retry;
  133. X    struct sockaddr_in sin;
  134. X    unsigned short port;
  135. X    int flags;
  136. X    extern nfs_fh *root_fh();
  137. X    char fs_hostname[MAXHOSTNAMELEN+MAXPATHLEN+1];
  138. X
  139. X    MTYPE_TYPE type = MOUNT_TYPE_NFS;
  140. X
  141. X    bzero((voidp) &nfs_args, sizeof(nfs_args));    /* Paranoid */
  142. X
  143. X    mnt.mnt_dir = dir;
  144. X    mnt.mnt_fsname = fs_name;
  145. X    mnt.mnt_type = MNTTYPE_AUTO;
  146. X    mnt.mnt_opts = opts;
  147. X    mnt.mnt_freq = 0;
  148. X    mnt.mnt_passno = 0;
  149. X
  150. X    retry = hasmntval(&mnt, "retry");
  151. X    if (retry <= 0)
  152. X        retry = 2;    /* XXX */
  153. X
  154. X    /*
  155. X     * get fhandle of remote path for automount point
  156. X     */
  157. X    nfs_args.fh = (NFS_FH_TYPE) root_fh(fs_name);
  158. X
  159. X    if (!nfs_args.fh) {
  160. X        plog(XLOG_FATAL, "Can't find root file handle for %s", fs_name);
  161. X        return EINVAL;
  162. X    }
  163. X
  164. X    /*
  165. X     * Create sockaddr to point to the local machine.  127.0.0.1
  166. X     * is not used since that will not work in HP-UX clusters and
  167. X     * this is no more expensive.
  168. X     */
  169. X    bzero((voidp) &sin, sizeof(sin));
  170. X    sin.sin_family = AF_INET;
  171. X    sin.sin_addr = myipaddr;
  172. X    if (port = hasmntval(&mnt, "port")) {
  173. X        sin.sin_port = htons(port);
  174. X    } else {
  175. X        plog(XLOG_ERROR, "no port number specified for %s", fs_name);
  176. X        return EINVAL;
  177. X    }
  178. X
  179. X    /*
  180. X     * set mount args
  181. X     */
  182. X    nfs_args.addr = &sin;
  183. X
  184. X    /*
  185. X     * Make a ``hostname'' string for the kernel
  186. X     */
  187. X#ifdef SHORT_MOUNT_NAME
  188. X    sprintf(fs_hostname, "amd:%d", mypid);
  189. X#else
  190. X    sprintf(fs_hostname, "pid%d@%s:%s", mypid, hostname, dir);
  191. X#endif
  192. X    nfs_args.hostname = fs_hostname;
  193. X    nfs_args.flags |= NFSMNT_HOSTNAME;
  194. X#ifdef HOSTNAMESZ
  195. X    /*
  196. X     * Most kernels have a name length restriction.
  197. X     */
  198. X    if (strlen(fs_hostname) >= HOSTNAMESZ)
  199. X        strcpy(fs_hostname + HOSTNAMESZ - 3, "..");
  200. X#endif
  201. X
  202. X    /*
  203. X     * Parse a subset of the standard nfs options.  The
  204. X     * others are probably irrelevant for this application
  205. X     */
  206. X    if (nfs_args.timeo = hasmntval(&mnt, "timeo"))
  207. X        nfs_args.flags |= NFSMNT_TIMEO;
  208. X
  209. X    if (nfs_args.retrans = hasmntval(&mnt, "retrans"))
  210. X        nfs_args.flags |= NFSMNT_RETRANS;
  211. X
  212. X#if defined(NFSMNT_ACREGMIN) && defined(NFSMNT_ACREGMAX)
  213. X    /*
  214. X     * Don't cache attributes - they are changing under
  215. X     * the kernel's feet...
  216. X     */
  217. X    nfs_args.acregmin = nfs_args.acregmax = 1;
  218. X    nfs_args.flags |= NFSMNT_ACREGMIN|NFSMNT_ACREGMAX;
  219. X#endif
  220. X    /*
  221. X     * These two are constructed internally by the calling routine
  222. X     */
  223. X    if (hasmntopt(&mnt, MNTOPT_SOFT) != NULL)
  224. X        nfs_args.flags |= NFSMNT_SOFT;
  225. X
  226. X#ifdef MNTOPT_INTR
  227. X    if (hasmntopt(&mnt, MNTOPT_INTR) != NULL)
  228. X        nfs_args.flags |= NFSMNT_INT;
  229. X#endif
  230. X
  231. X    flags = compute_mount_flags(&mnt);
  232. X#ifdef ULTRIX_HACK
  233. X    nfs_args.gfs_flags = flags;
  234. X    flags &= M_RDONLY;
  235. X    if (flags & M_RDONLY)
  236. X        nfs_args.flags |= NFSMNT_RONLY;
  237. X#endif
  238. X    return mount_fs(&mnt, flags, (caddr_t) &nfs_args, retry, type);
  239. X}
  240. X
  241. Xstatic int afs_mount(mp)
  242. Xam_node *mp;
  243. X{
  244. X    mntfs *mf = mp->am_mnt;
  245. X
  246. X    /*
  247. X     * There are two cases to consider...
  248. X     */
  249. X    if (mp->am_parent && mp->am_parent->am_parent) {
  250. X        /*
  251. X         * If this am_node has a parent which is not the root node, in
  252. X         * which case we are supplying a pseudo-directory, in which
  253. X         * case no action is needed.  Pseudo-directories are used to
  254. X         * provide some structure to the automounted directories instead
  255. X         * of putting them all in the top-level automount directory.
  256. X         */
  257. X        mp->am_parent->am_mnt->mf_fattr.nlink++;
  258. X        /*
  259. X         * Info field of . means use parent's info field.
  260. X         */
  261. X        if (mf->mf_info[0] == '.' && mf->mf_info[1] == '\0')
  262. X            mf->mf_info = strealloc(mf->mf_info, mp->am_parent->am_mnt->mf_info);
  263. X        /*
  264. X         * Compute prefix:
  265. X         *
  266. X         * If there is an option prefix then use that else
  267. X         * If the parent had a prefix then use that with name
  268. X         *    of this node appended else
  269. X         * Use the name of this node.
  270. X         *
  271. X         * That means if you want no prefix you must say so
  272. X         * in the map.
  273. X         */
  274. X        if (mf->mf_fo->opt_pref) {
  275. X            /*
  276. X             * the prefix specified as an option
  277. X             */
  278. X            mp->am_pref = strdup(mf->mf_fo->opt_pref);
  279. X        } else {
  280. X            /*
  281. X             * else the parent's prefix
  282. X             * followed by the name
  283. X             * followed by /
  284. X             */
  285. X            char *ppref = mp->am_parent->am_pref;
  286. X            if (ppref == 0)
  287. X                ppref = "";
  288. X            mp->am_pref = str3cat((char *) 0, ppref, mp->am_name, "/");
  289. X        }
  290. X    } else {
  291. X        /*
  292. X         * Otherwise, we are mounting the automounter.  In which case
  293. X         * we need to make sure the mount directory exists, construct
  294. X         * the mount options and call the mount_afs routine.
  295. X         */
  296. X        struct stat stb;
  297. X        char opts[256];
  298. X        int error;
  299. X
  300. X        /*
  301. X         * Top-level mount - so make
  302. X         * sure the mount point exists
  303. X         * and is a directory.
  304. X         */
  305. X        error = mkdirs(mp->am_path, 0555);
  306. X        if (error)
  307. X            return error;
  308. X        mp->am_flags |= AMF_MKPATH;
  309. X
  310. X        if (stat(mp->am_path, &stb) < 0) {
  311. X            return errno;
  312. X        } else if ((stb.st_mode & S_IFMT) != S_IFDIR) {
  313. X            plog(XLOG_WARNING, "%s is not a directory", mp->am_path);
  314. X            return ENOTDIR;
  315. X        }
  316. X
  317. X        mf->mf_mount = strealloc(mf->mf_mount, mp->am_path);
  318. X
  319. X        /*
  320. X         * Construct some mount options
  321. X         */
  322. X        sprintf(opts,
  323. X#ifdef MNTOPT_INTR
  324. X            "%s,%s,%s=%d,%s=%d,%s=%d,%sdirect",
  325. X            MNTOPT_INTR,
  326. X#else
  327. X            "%s,%s=%d,%s=%d,%s=%d,%sdirect",
  328. X#endif
  329. X#ifdef AUTOMOUNT_RO
  330. X            MNTOPT_RO,    /* You don't really want this... */
  331. X#else
  332. X            "rw",
  333. X#endif
  334. X            "port", nfs_port,
  335. X            "timeo", afs_timeo,
  336. X            "retrans", afs_retrans,
  337. X            mf->mf_ops == &afs_ops ? "in" : "");
  338. X
  339. X        error = mount_afs(mp->am_path, mp->am_name, opts);
  340. X        if (error) {
  341. X            errno = error;
  342. X            plog(XLOG_FATAL, "mount_afs: %m");
  343. X            return error;
  344. X        }
  345. X        mp->am_name = pid_fsname;
  346. X    }
  347. X
  348. X    /*
  349. X     * Build a new map cache for this node, or re-use
  350. X     * an existing cache for the same map.
  351. X     */
  352. X    { char *cache;
  353. X      if (mf->mf_fo->opt_cache)
  354. X          cache = mf->mf_fo->opt_cache;
  355. X      else
  356. X          cache = "none";
  357. X      mf->mf_private = (voidp) mapc_find(mf->mf_info, cache);
  358. X      mf->mf_prfree = mapc_free;
  359. X    }
  360. X
  361. X    return 0;
  362. X}
  363. X
  364. X/*
  365. X * Unmount an automount node
  366. X */
  367. Xstatic int afs_umount(mp)
  368. Xam_node *mp;
  369. X{
  370. X    int error;
  371. X
  372. X    /*
  373. X     * If this is a pseudo-directory then just adjust the link count
  374. X     * in the parent, otherwise call the generic unmount routine
  375. X     */
  376. X    if (!mp->am_parent) {
  377. X        error = 0;
  378. X    } else if (mp->am_parent && mp->am_parent->am_parent) {
  379. X        --mp->am_parent->am_mnt->mf_fattr.nlink;
  380. X        error = 0;
  381. X    } else {
  382. X        struct stat stb;
  383. Xagain:
  384. X        /*
  385. X         * The lstat is needed if this mount is type=direct.
  386. X         * When that happens, the kernel cache gets confused
  387. X         * between the underlying type (dir) and the mounted
  388. X         * type (link) and so needs to be re-synced before
  389. X         * the unmount.  This is all because the unmount system
  390. X         * call follows links and so can't actually unmount
  391. X         * a link (stupid!).  It was noted that doing and ls -ld
  392. X         * of the mount point to see why things were not working
  393. X         * actually fixed the problem - so simulate an ls -ld here.
  394. X         */
  395. X        if (lstat(mp->am_path, &stb) < 0) {
  396. X#ifdef DEBUG
  397. X            dlog("lstat(%s): %m", mp->am_path);
  398. X#endif
  399. X        }
  400. X        error = UMOUNT_FS(mp->am_path);
  401. X        if (error == EBUSY) {
  402. X            plog(XLOG_WARNING, "afs_unmount retrying %s in 1s", mp->am_path);
  403. X            sleep(1);    /* XXX */
  404. X            goto again;
  405. X        }
  406. X    }
  407. X
  408. X    return error;
  409. X}
  410. X
  411. X/*
  412. X * Unmount an automount node
  413. X */
  414. Xstatic void afs_umounted(mp)
  415. Xam_node *mp;
  416. X{
  417. X    /*
  418. X     * If this is a pseudo-directory then just adjust the link count
  419. X     * in the parent, otherwise call the generic unmount routine
  420. X     */
  421. X    if (mp->am_parent && mp->am_parent->am_parent)
  422. X        --mp->am_parent->am_mnt->mf_fattr.nlink;
  423. X}
  424. X
  425. X/*
  426. X * Mounting a file system may take a significant period of time.  The
  427. X * problem is that if this is done in the main process thread then
  428. X * the entire automounter could be blocked, possibly hanging lots of
  429. X * processes on the system.  Instead we use a continuation scheme to
  430. X * allow mounts to be attempted in a sub-process.  When the sub-process
  431. X * exits we pick up the exit status (by convention a UN*X error number)
  432. X * and continue in a notifier.  The notifier gets handed a data structure
  433. X * and can then determine whether the mount was successful or not.  If
  434. X * not, it updates the data structure and tries again until there are no
  435. X * more ways to try the mount, or some other permanent error occurs.
  436. X * In the mean time no RPC reply is sent, even after the mount is succesful.
  437. X * We rely on the RPC retry mechanism to resend the lookup request which
  438. X * can then be handled.
  439. X */
  440. X
  441. X
  442. Xstruct continuation {
  443. X    char **ivec;        /* Current mount info */
  444. X    am_node *mp;        /* Node we are trying to mount */
  445. X    char *key;        /* Map key */
  446. X    char *info;        /* Info string */
  447. X    char **xivec;        /* Saved strsplit vector */
  448. X    char *opts;        /* Mount options */
  449. X    am_opts fs_opts;    /* Filesystem options */
  450. X    char *def_opts;        /* Default options */
  451. X    int retry;        /* Try again? */
  452. X    int tried;        /* Have we tried any yet? */
  453. X    time_t start;        /* Time we started this mount */
  454. X    int callout;        /* Callout identifier */
  455. X};
  456. X
  457. X/*
  458. X * Discard an old continuation
  459. X */
  460. Xstatic void free_continuation(cp)
  461. Xstruct continuation *cp;
  462. X{
  463. X    if (cp->callout)
  464. X        untimeout(cp->callout);
  465. X    free((voidp) cp->key);
  466. X    free((voidp) cp->xivec);
  467. X    free((voidp) cp->info);
  468. X    free((voidp) cp->opts);
  469. X    free((voidp) cp->def_opts);
  470. X    free_opts(&cp->fs_opts);
  471. X    free((voidp) cp);
  472. X}
  473. X
  474. Xstatic int afs_bgmount P((struct continuation*, int));
  475. X
  476. X/*
  477. X * Discard the underlying mount point and replace
  478. X * with a reference to an error filesystem.
  479. X */
  480. Xstatic void assign_error_mntfs(mp)
  481. Xam_node *mp;
  482. X{
  483. X    if (mp->am_error > 0) {
  484. X        /*
  485. X         * Save the old error code
  486. X         */
  487. X        int error = mp->am_error;
  488. X        /*
  489. X         * Discard the old filesystem
  490. X         */
  491. X        free_mntfs(mp->am_mnt);
  492. X        /*
  493. X         * Allocate a new error reference
  494. X         */
  495. X        mp->am_mnt = new_mntfs();
  496. X        /*
  497. X         * Put back the error code
  498. X         */
  499. X        mp->am_mnt->mf_error = error;
  500. X        mp->am_mnt->mf_flags |= MFF_ERROR;
  501. X        /*
  502. X         * Zero the error in the mount point
  503. X         */
  504. X        mp->am_error = 0;
  505. X    }
  506. X}
  507. X
  508. X/*
  509. X * The continuation function.  This is called by
  510. X * the task notifier when a background mount attempt
  511. X * completes.
  512. X */
  513. Xstatic void afs_cont(rc, term, closure)
  514. Xint rc;
  515. Xint term;
  516. Xvoidp closure;
  517. X{
  518. X    struct continuation *cp = (struct continuation *) closure;
  519. X    mntfs *mf = cp->mp->am_mnt;
  520. X
  521. X    /*
  522. X     * Definitely not trying to mount at the moment
  523. X     */
  524. X    mf->mf_flags &= ~MFF_MOUNTING;
  525. X    /*
  526. X     * While we are mounting - try to avoid race conditions
  527. X     */
  528. X    new_ttl(cp->mp);
  529. X
  530. X    /*
  531. X     * Wakeup anything waiting for this mount
  532. X     */
  533. X    wakeup((voidp) mf);
  534. X
  535. X    /*
  536. X     * Check for termination signal or exit status...
  537. X     */
  538. X    if (rc || term) {
  539. X        if (term) {
  540. X            /*
  541. X             * Not sure what to do for an error code.
  542. X             */
  543. X            mf->mf_error = EIO;    /* XXX ? */
  544. X            mf->mf_flags |= MFF_ERROR;
  545. X            plog(XLOG_ERROR, "mount for %s got signal %d", cp->mp->am_path, term);
  546. X        } else {
  547. X            /*
  548. X             * Check for exit status...
  549. X             */
  550. X            mf->mf_error = rc;
  551. X            mf->mf_flags |= MFF_ERROR;
  552. X            errno = rc;    /* XXX */
  553. X            plog(XLOG_ERROR, "%s: mount (afs_cont): %m", cp->mp->am_path);
  554. X        }
  555. X
  556. X        /*
  557. X         * If we get here then that attempt didn't work, so
  558. X         * move the info vector pointer along by one and
  559. X         * call the background mount routine again
  560. X         */
  561. X        amd_stats.d_merr++;
  562. X        cp->ivec++;
  563. X        (void) afs_bgmount(cp, 0);
  564. X        assign_error_mntfs(cp->mp);
  565. X    } else {
  566. X        /*
  567. X         * The mount worked.
  568. X         */
  569. X        am_mounted(cp->mp);
  570. X        free_continuation(cp);
  571. X    }
  572. X
  573. X    reschedule_timeout_mp();
  574. X}
  575. X
  576. X/*
  577. X * Retry a mount
  578. X */
  579. X/*ARGSUSED*/
  580. Xstatic void afs_retry(rc, term, closure)
  581. Xint rc;
  582. Xint term;
  583. Xvoidp closure;
  584. X{
  585. X    struct continuation *cp = (struct continuation *) closure;
  586. X    int error = 0;
  587. X
  588. X#ifdef DEBUG
  589. X    dlog("Commencing retry for mount of %s", cp->mp->am_path);
  590. X#endif
  591. X
  592. X    if ((cp->start + ALLOWED_MOUNT_TIME) < clocktime()) {
  593. X        /*
  594. X         * The entire mount has timed out.
  595. X         * Set the error code and skip past
  596. X         * all the info vectors so that
  597. X         * afs_bgmount will not have any more
  598. X         * ways to try the mount, so causing
  599. X         * an error.
  600. X         */
  601. X        plog(XLOG_INFO, "mount of \"%s\" has timed out", cp->mp->am_path);
  602. X        error = ETIMEDOUT;
  603. X        new_ttl(cp->mp);
  604. X        while (*cp->ivec)
  605. X            cp->ivec++;
  606. X    }
  607. X
  608. X    (void) afs_bgmount(cp, error);
  609. X    reschedule_timeout_mp();
  610. X}
  611. X
  612. X/*
  613. X * Try to mount a file system.  Can be called
  614. X * directly or in a sub-process by run_task
  615. X */
  616. Xstatic int try_mount(mp)
  617. Xam_node *mp;
  618. X{
  619. X    /*
  620. X     * Mount it!
  621. X     */
  622. X    int error;
  623. X
  624. X    error = mount_node(mp);
  625. X#ifdef DEBUG
  626. X    if (error) {
  627. X        errno = error;
  628. X        dlog("afs call to mount_node failed: %m");
  629. X    }
  630. X#endif
  631. X    return error;
  632. X}
  633. X
  634. X/*
  635. X * Pick a file system to try mounting and
  636. X * do that in the background if necessary
  637. X *
  638. XFor each location:
  639. X    if it is new -defaults then
  640. X        extract and process
  641. X        continue;
  642. X    fi
  643. X    if it is a cut then
  644. X        if a location has been tried then
  645. X            break;
  646. X        fi
  647. X        continue;
  648. X    fi
  649. X    parse mount location
  650. X    discard previous mount location if required
  651. X    find matching mounted filesystem
  652. X    if not applicable then
  653. X        this_error = No such file or directory
  654. X        continue
  655. X    fi
  656. X    if the filesystem failed to be mounted then
  657. X        this_error = error from filesystem
  658. X    elif the filesystem is mounting or unmounting then
  659. X        this_error = -1
  660. X    elif the fileserver is down then
  661. X        this_error = -1
  662. X    elif the filesystem is already mounted
  663. X        this_error = 0
  664. X        break
  665. X    fi
  666. X    if no error on this mount then
  667. X        this_error = initialise mount point
  668. X    fi
  669. X    if no error on this mount and mount is delayed then
  670. X        this_error = -1
  671. X    fi
  672. X    if this_error < 0 then
  673. X        retry = true
  674. X    fi
  675. X    if no error on this mount then
  676. X        make mount point if required
  677. X    fi
  678. X    if no error on this mount then
  679. X        if mount in background then
  680. X            run mount in background
  681. X            return -1
  682. X        else
  683. X            this_error = mount in foreground
  684. X        fi
  685. X    fi
  686. X    if an error occured on this mount then
  687. X        update stats
  688. X        save error in mount point
  689. X    fi
  690. Xendfor
  691. X */
  692. X
  693. Xstatic int afs_bgmount(cp, mpe)
  694. Xstruct continuation *cp;
  695. Xint mpe;
  696. X{
  697. X    mntfs *mf = cp->mp->am_mnt;    /* Current mntfs */
  698. X    mntfs *mf_retry = 0;        /* First mntfs which needed retrying */
  699. X    int this_error = -1;        /* Per-mount error */
  700. X    int hard_error = -1;
  701. X    int mp_error = mpe;
  702. X
  703. X    /*
  704. X     * Try to mount each location.
  705. X     * At the end:
  706. X     * hard_error == 0 indicates something was mounted.
  707. X     * hard_error > 0 indicates everything failed with a hard error
  708. X     * hard_error < 0 indicates nothing could be mounted now
  709. X     */
  710. X    for (; this_error && *cp->ivec; cp->ivec++) {
  711. X        am_ops *p;
  712. X        am_node *mp = cp->mp;
  713. X        char *link_dir;
  714. X        int dont_retry;
  715. X
  716. X        if (hard_error < 0)
  717. X            hard_error = this_error;
  718. X
  719. X        this_error = -1;
  720. X
  721. X        if (**cp->ivec == '-') {
  722. X            /*
  723. X             * Pick up new defaults
  724. X             */
  725. X            if (cp->opts && *cp->opts)
  726. X                cp->def_opts = str3cat(cp->def_opts, cp->opts, ";", *cp->ivec+1);
  727. X            else
  728. X                cp->def_opts = strealloc(cp->def_opts, *cp->ivec+1);
  729. X#ifdef DEBUG
  730. X            dlog("Setting def_opts to \"%s\"", cp->def_opts);
  731. X#endif
  732. X            continue;
  733. X        }
  734. X
  735. X        /*
  736. X         * If a mount has been attempted, and we find
  737. X         * a cut then don't try any more locations.
  738. X         */
  739. X        if (strcmp(*cp->ivec, "/") == 0 || strcmp(*cp->ivec, "||") == 0) {
  740. X            if (cp->tried) {
  741. X#ifdef DEBUG
  742. X                dlog("Cut: not trying any more locations for %s",
  743. X                    mp->am_path);
  744. X#endif
  745. X                break;
  746. X            }
  747. X            continue;
  748. X        }
  749. X
  750. X#ifdef SUNOS4_COMPAT
  751. X        /*
  752. X         * By default, you only get this bit on SunOS4.
  753. X         * If you want this anyway, then define SUNOS4_COMPAT
  754. X         * in the relevant "os-blah.h" file.
  755. X         *
  756. X         * We make the observation that if the local key line contains
  757. X         * no '=' signs then either it is sick, or it is a SunOS4-style
  758. X         * "host:fs[:link]" line.  In the latter case the am_opts field
  759. X         * is also assumed to be in old-style, so you can't mix & match.
  760. X         * You can use ${} expansions for the fs and link bits though...
  761. X         *
  762. X         * Actually, this doesn't really cover all the possibilities for
  763. X         * the latest SunOS automounter and it is debatable whether there
  764. X         * is any point bothering.
  765. X         */
  766. X        if (strchr(*cp->ivec, '=') == 0)
  767. X            p = sunos4_match(&cp->fs_opts, *cp->ivec, cp->def_opts, mp->am_path, cp->key, mp->am_parent->am_mnt->mf_info);
  768. X        else
  769. X#endif /* SUNOS4_COMPAT */
  770. X            p = ops_match(&cp->fs_opts, *cp->ivec, cp->def_opts, mp->am_path, cp->key, mp->am_parent->am_mnt->mf_info);
  771. X
  772. X        /*
  773. X         * Find a mounted filesystem for this node.
  774. X         */
  775. X        mp->am_mnt = mf = realloc_mntfs(mf, p, &cp->fs_opts, cp->fs_opts.opt_fs,
  776. X                        cp->fs_opts.fs_mtab, cp->opts);
  777. X
  778. X        p = mf->mf_ops;
  779. X#ifdef DEBUG
  780. X        dlog("Got a hit with %s", p->fs_type);
  781. X#endif
  782. X        /*
  783. X         * Note whether this is a real mount attempt
  784. X         */
  785. X        if (p == &efs_ops) {
  786. X            plog(XLOG_MAP, "Map entry %s for %s failed to match", *cp->ivec, mp->am_path);
  787. X            if (this_error <= 0)
  788. X                this_error = ENOENT;
  789. X            continue;
  790. X        } else {
  791. X            if (cp->fs_opts.fs_mtab) {
  792. X                plog(XLOG_MAP, "Trying mount of %s on %s fstype %s",
  793. X                    cp->fs_opts.fs_mtab, mp->am_path, p->fs_type);
  794. X            }
  795. X            cp->tried = TRUE;
  796. X        }
  797. X
  798. X        this_error = 0;
  799. X        dont_retry = FALSE;
  800. X
  801. X        if (mp->am_link) {
  802. X            free(mp->am_link);
  803. X            mp->am_link = 0;
  804. X        }
  805. X
  806. X        link_dir = mf->mf_fo->opt_sublink;
  807. X
  808. X        if (link_dir && *link_dir) {
  809. X            if (*link_dir == '/') {
  810. X                mp->am_link = strdup(link_dir);
  811. X            } else {
  812. X                mp->am_link = str3cat((char *) 0,
  813. X                    mf->mf_fo->opt_fs, "/", link_dir);
  814. X            }
  815. X        }
  816. X
  817. X        if (mf->mf_error > 0) {
  818. X            this_error = mf->mf_error;
  819. X        } else if (mf->mf_flags & (MFF_MOUNTING|MFF_UNMOUNTING)) {
  820. X            /*
  821. X             * Still mounting - retry later
  822. X             */
  823. X#ifdef DEBUG
  824. X            dlog("Duplicate pending fstype %s mount", p->fs_type);
  825. X#endif
  826. X            this_error = -1;
  827. X        } else if (FSRV_ISDOWN(mf->mf_server)) {
  828. X            /*
  829. X             * Would just mount from the same place
  830. X             * as a hung mount - so give up
  831. X             */
  832. X#ifdef DEBUG
  833. X            dlog("%s is already hung - giving up", mf->mf_mount);
  834. X#endif
  835. X            mp_error = EWOULDBLOCK;
  836. X            dont_retry = TRUE;
  837. X            this_error = -1;
  838. X        } else if (mf->mf_flags & MFF_MOUNTED) {
  839. X#ifdef DEBUG
  840. X            dlog("duplicate mount of \"%s\" ...", mf->mf_info);
  841. X#endif
  842. X            this_error = 0;
  843. X            break;
  844. X        }
  845. X
  846. X        /*
  847. X         * Will usually need to play around with the mount nodes
  848. X         * file attribute structure.  This must be done here.
  849. X         */
  850. X        if (!this_error) {
  851. X            /*
  852. X             * Fill in attribute fields
  853. X             */
  854. X            mf->mf_fattr.type = NFLNK;
  855. X            mf->mf_fattr.mode = NFSMODE_LNK | 0777;
  856. X            mf->mf_fattr.nlink = 1;
  857. X            mf->mf_fattr.size = MAXPATHLEN / 4;    /* Conservative */
  858. X            mf->mf_fattr.fileid = mp->am_gen;
  859. X
  860. X            if (p->fs_init)
  861. X                this_error = (*p->fs_init)(mf);
  862. X        }
  863. X
  864. X        if (!this_error && mf->mf_fo->opt_delay) {
  865. X            /*
  866. X             * If there is a delay timer on the mount
  867. X             * then don't try to mount if the timer
  868. X             * has not expired.
  869. X             */
  870. X            int i = atoi(mf->mf_fo->opt_delay);
  871. X            if (i > 0 && (cp->start + i) < clocktime()) {
  872. X#ifdef DEBUG
  873. X                dlog("Mount of %s delayed by %ds", mf->mf_mount, i);
  874. X#endif
  875. X                this_error = -1;
  876. X            }
  877. X        }
  878. X
  879. X        if (this_error < 0 && !dont_retry) {
  880. X            if (!mf_retry)
  881. X                mf_retry = dup_mntfs(mf);
  882. X            cp->retry = TRUE;
  883. X        }
  884. X
  885. X        if (!this_error) {
  886. X            /*
  887. X             * If the directory is not yet made and
  888. X             * it needs to be made, then make it!
  889. X             */
  890. X             if (!(mf->mf_flags & MFF_MKMNT) &&
  891. X                     p->fs_flags & FS_MKMNT) {
  892. X                this_error = mkdirs(mf->mf_mount, 0555);
  893. X                if (!this_error)
  894. X                    mf->mf_flags |= MFF_MKMNT;
  895. X            }
  896. X        }
  897. X
  898. X        if (!this_error)
  899. X        if (p->fs_flags & FS_MBACKGROUND) {
  900. X            mf->mf_flags |= MFF_MOUNTING;    /*XXX*/
  901. X#ifdef DEBUG
  902. X            dlog("backgrounding mount of \"%s\"", mf->mf_info);
  903. X#endif
  904. X            if (cp->callout) {
  905. X                untimeout(cp->callout);
  906. X                cp->callout = 0;
  907. X            }
  908. X            run_task(try_mount, (voidp) mp, afs_cont, (voidp) cp);
  909. X            if (mf_retry) free_mntfs(mf_retry);
  910. X            return -1;
  911. X        } else {
  912. X#ifdef DEBUG
  913. X            dlog("foreground mount of \"%s\" ...", mf->mf_info);
  914. X#endif
  915. X            this_error = try_mount(mp);
  916. X        }
  917. X
  918. X        if (this_error >= 0) {
  919. X            if (this_error > 0) {
  920. X                amd_stats.d_merr++;
  921. X                if (mf != mf_retry) {
  922. X                    mf->mf_error = this_error;
  923. X                    mf->mf_flags |= MFF_ERROR;
  924. X                }
  925. X            }
  926. X            /*
  927. X             * Wakeup anything waiting for this mount
  928. X             */
  929. X            wakeup((voidp) mf);
  930. X        }
  931. X    }
  932. X
  933. X    if (this_error && cp->retry) {
  934. X        free_mntfs(mf);
  935. X        mf = cp->mp->am_mnt = mf_retry;
  936. X        /*
  937. X         * Not retrying again (so far)
  938. X         */
  939. X        cp->retry = FALSE;
  940. X        cp->tried = FALSE;
  941. X        /*
  942. X         * Start at the beginning.
  943. X         * Rewind the location vector and
  944. X         * reset the default options.
  945. X         */
  946. X        cp->ivec = cp->xivec;
  947. X        cp->def_opts = strealloc(cp->def_opts, cp->opts);
  948. X        /*
  949. X         * Arrange that afs_bgmount is called
  950. X         * after anything else happens.
  951. X         */
  952. X#ifdef DEBUG
  953. X        dlog("Arranging to retry mount of %s", cp->mp->am_path);
  954. X#endif
  955. X        sched_task(afs_retry, (voidp) cp, (voidp) mf);
  956. X        if (cp->callout)
  957. X            untimeout(cp->callout);
  958. X        cp->callout = timeout(RETRY_INTERVAL, wakeup, (voidp) mf);
  959. X
  960. X        cp->mp->am_ttl = clocktime() + RETRY_INTERVAL;
  961. X
  962. X        /*
  963. X         * Not done yet - so don't return anything
  964. X         */
  965. X        return -1;
  966. X    }
  967. X
  968. X    /*
  969. X     * Discard handle on duff filesystem.
  970. X     * This should never happen since it
  971. X     * should be caught by the case above.
  972. X     */
  973. X    if (mf_retry) {
  974. X        plog(XLOG_ERROR, "discarding a retry mntfs for %s", mf_retry->mf_mount);
  975. X        free_mntfs(mf_retry);
  976. X    }
  977. X
  978. X    if (hard_error < 0 || !this_error)
  979. X        hard_error = this_error;
  980. X
  981. X    /*
  982. X     * If we get here, then either the mount succeeded or
  983. X     * there is no more mount information available.
  984. X     */
  985. X    if (hard_error < 0 && mp_error)
  986. X        hard_error = cp->mp->am_error = mp_error;
  987. X    if (hard_error > 0) {
  988. X        /*
  989. X         * Set a small(ish) timeout on an error node if
  990. X         * the error was not a time out.
  991. X         */
  992. X        switch (hard_error) {
  993. X        case ETIMEDOUT:
  994. X        case EWOULDBLOCK:
  995. X            cp->mp->am_timeo = 5;
  996. X            break;
  997. X        default:
  998. X            cp->mp->am_timeo = 17;
  999. X            break;
  1000. X        }
  1001. X        cp->mp->am_timeo_w = 0;
  1002. X    }
  1003. X
  1004. X    /*
  1005. X     * Make sure that the error value in the mntfs has a
  1006. X     * reasonable value.
  1007. X     */
  1008. X    if (mf->mf_error < 0) {
  1009. X        mf->mf_error = hard_error;
  1010. X        if (hard_error)
  1011. X            mf->mf_flags |= MFF_ERROR;
  1012. X    }
  1013. X
  1014. X    /*
  1015. X     * In any case we don't need the continuation any more
  1016. X     */
  1017. X    free_continuation(cp);
  1018. X
  1019. X    return hard_error;
  1020. X}
  1021. X
  1022. X/*
  1023. X * Automount interface to RPC lookup routine
  1024. X */
  1025. Xstatic am_node *afs_lookuppn(mp, fname, error_return, op)
  1026. Xam_node *mp;
  1027. Xchar *fname;
  1028. Xint *error_return;
  1029. Xint op;
  1030. X{
  1031. X#define ereturn(x) { *error_return = x; return 0; }
  1032. X
  1033. X    /*
  1034. X     * Find the corresponding entry and return
  1035. X     * the file handle for it.
  1036. X     */
  1037. X    am_node *ap, *new_mp, *ap_hung;
  1038. X    char *info;            /* Mount info - where to get the file system */
  1039. X    char **ivec, **xivec;        /* Split version of info */
  1040. X    char *opts;            /* Mount options */
  1041. X    int error = 0;            /* Error so far */
  1042. X    char path_name[MAXPATHLEN];    /* General path name buffer */
  1043. X    char *pfname;            /* Path for database lookup */
  1044. X    struct continuation *cp;    /* Continuation structure if we need to mount */
  1045. X    int in_progress = 0;        /* # of (un)mount in progress */
  1046. X    char *dflts;
  1047. X    mntfs *mf;
  1048. X
  1049. X#ifdef DEBUG
  1050. X    dlog("in afs_lookuppn");
  1051. X#endif
  1052. X
  1053. X    /*
  1054. X     * If the server is shutting down
  1055. X     * then don't return information
  1056. X     * about the mount point.
  1057. X     */
  1058. X    if (amd_state == Finishing) {
  1059. X#ifdef DEBUG
  1060. X        dlog("%s/%s mount ignored - going down",
  1061. X            mp->am_path, fname);
  1062. X#endif
  1063. X        ereturn(ENOENT);
  1064. X    }
  1065. X
  1066. X    /*
  1067. X     * Handle special case of "." and ".."
  1068. X     */
  1069. X    if (fname[0] == '.') {
  1070. X        if (fname[1] == '\0')
  1071. X            return mp;    /* "." is the current node */
  1072. X        if (fname[1] == '.' && fname[2] == '\0') {
  1073. X            if (mp->am_parent) {
  1074. X#ifdef DEBUG
  1075. X                dlog(".. in %s gives %s", mp->am_path, mp->am_parent->am_path);
  1076. X#endif
  1077. X                return mp->am_parent;    /* ".." is the parent node */
  1078. X            }
  1079. X            ereturn(ESTALE);
  1080. X        }
  1081. X    }
  1082. X
  1083. X    /*
  1084. X     * Check for valid key name.
  1085. X     * If it is invalid then pretend it doesn't exist.
  1086. X     */
  1087. X    if (!valid_key(fname)) {
  1088. X        plog(XLOG_WARNING, "Key \"%s\" contains a disallowed character", fname);
  1089. X        ereturn(ENOENT);
  1090. X    }
  1091. X
  1092. X    /*
  1093. X     * Expand key name.
  1094. X     * fname is now a private copy.
  1095. X     */
  1096. X    fname = expand_key(fname);
  1097. X
  1098. X    for (ap_hung = 0, ap = mp->am_child; ap; ap = ap->am_osib) {
  1099. X        /*
  1100. X         * Otherwise search children of this node
  1101. X         */
  1102. X        if (FSTREQ(ap->am_name, fname)) {
  1103. X            mf = ap->am_mnt;
  1104. X            if (ap->am_error) {
  1105. X                error = ap->am_error;
  1106. X                continue;
  1107. X            }
  1108. X
  1109. X            /*
  1110. X             * If the error code is undefined then it must be
  1111. X             * in progress.
  1112. X             */
  1113. X            if (mf->mf_error < 0)
  1114. X                goto in_progrss;
  1115. X
  1116. X            /*
  1117. X             * Check for a hung node
  1118. X             */
  1119. X            if (FSRV_ISDOWN(mf->mf_server)) {
  1120. X                ap_hung = ap;
  1121. X                continue;
  1122. X            }
  1123. X
  1124. X            /*
  1125. X             * If there was a previous error with this node
  1126. X             * then return that error code.
  1127. X             */
  1128. X            if (mf->mf_flags & MFF_ERROR) {
  1129. X                error = mf->mf_error;
  1130. X                continue;
  1131. X            }
  1132. X
  1133. X            if (!(mf->mf_flags & MFF_MOUNTED) /*|| (mf->mf_flags & MFF_UNMOUNTING)*/) {
  1134. Xin_progrss:
  1135. X                /*
  1136. X                 * If the fs is not mounted or it is unmounting then there
  1137. X                 * is a background (un)mount in progress.  In this case
  1138. X                 * we just drop the RPC request (return nil) and
  1139. X                 * wait for a retry, by which time the (un)mount may
  1140. X                 * have completed.
  1141. X                 */
  1142. X#ifdef DEBUG
  1143. X                dlog("ignoring mount of %s in %s -- in progress",
  1144. X                    fname, mf->mf_mount);
  1145. X#endif
  1146. X                in_progress++;
  1147. X                continue;
  1148. X            }
  1149. X
  1150. X            /*
  1151. X             * Otherwise we have a hit: return the current mount point.
  1152. X             */
  1153. X#ifdef DEBUG
  1154. X            dlog("matched %s in %s", fname, ap->am_path);
  1155. X#endif
  1156. X            free(fname);
  1157. X            return ap;
  1158. X        }
  1159. X    }
  1160. X
  1161. X    if (in_progress) {
  1162. X#ifdef DEBUG
  1163. X        dlog("Waiting while %d mount(s) in progress", in_progress);
  1164. X#endif
  1165. X        free(fname);
  1166. X        ereturn(-1);
  1167. X    }
  1168. X
  1169. X    /*
  1170. X     * If an error occured then return it.
  1171. X     */
  1172. X    if (error) {
  1173. X#ifdef DEBUG
  1174. X        errno = error; /* XXX */
  1175. X        dlog("Returning error: %m", error);
  1176. X#endif
  1177. X        free(fname);
  1178. X        ereturn(error);
  1179. X    }
  1180. X
  1181. X    /*
  1182. X     * If doing a delete then don't create again!
  1183. X     */
  1184. X    switch (op) {
  1185. X    case VLOOK_DELETE:
  1186. X        ereturn(ENOENT);
  1187. X        break;
  1188. X
  1189. X    case VLOOK_CREATE:
  1190. X        break;
  1191. X
  1192. X    default:
  1193. X        plog(XLOG_FATAL, "Unknown op to afs_lookuppn: 0x%x", op);
  1194. X        ereturn(EINVAL);
  1195. X        break;
  1196. X    }
  1197. X
  1198. X    /*
  1199. X     * If the server is going down then just return,
  1200. X     * don't try to mount any more file systems
  1201. X     */
  1202. X    if ((int)amd_state >= (int)Finishing) {
  1203. X#ifdef DEBUG
  1204. X        dlog("not found - server going down anyway");
  1205. X#endif
  1206. X        free(fname);
  1207. X        ereturn(ENOENT);
  1208. X    }
  1209. X
  1210. X    /*
  1211. X     * If we get there then this is a reference to an,
  1212. X     * as yet, unknown name so we need to search the mount
  1213. X     * map for it.
  1214. X     */
  1215. X    if (mp->am_pref) {
  1216. X        sprintf(path_name, "%s%s", mp->am_pref, fname);
  1217. X        pfname = path_name;
  1218. X    } else {
  1219. X        pfname = fname;
  1220. X    }
  1221. X
  1222. X    mf = mp->am_mnt;
  1223. X
  1224. X#ifdef DEBUG
  1225. X    dlog("will search map info in %s to find %s", mf->mf_info, pfname);
  1226. X#endif
  1227. X    /*
  1228. X     * Consult the oracle for some mount information.
  1229. X     * info is malloc'ed and belongs to this routine.
  1230. X     * It ends up being free'd in free_continuation().
  1231. X     *
  1232. X     * Note that this may return -1 indicating that information
  1233. X     * is not yet available.
  1234. X     */
  1235. X    error = mapc_search((mnt_map*) mf->mf_private, pfname, &info);
  1236. X    if (error) {
  1237. X        plog(XLOG_MAP, "No map entry for %s", pfname);
  1238. X        free(fname);
  1239. X        ereturn(error);
  1240. X    }
  1241. X
  1242. X#ifdef DEBUG
  1243. X    dlog("mount info is %s", info);
  1244. X#endif
  1245. X
  1246. X    /*
  1247. X     * Split info into an argument vector.
  1248. X     * The vector is malloc'ed and belongs to
  1249. X     * this routine.  It is free'd in free_continuation()
  1250. X     */
  1251. X    xivec = ivec = strsplit(info, '\"');
  1252. X
  1253. X    /*
  1254. X     * Default error code...
  1255. X     */
  1256. X    if (ap_hung)
  1257. X        error = EWOULDBLOCK;
  1258. X    else
  1259. X        error = ENOENT;
  1260. X
  1261. X    /*
  1262. X     * Allocate a new map
  1263. X     */
  1264. X    new_mp = exported_ap_alloc();
  1265. X    if (new_mp == 0) {
  1266. X        free((voidp) xivec);
  1267. X        free((voidp) info);
  1268. X        free((voidp) fname);
  1269. X        ereturn(ENOSPC);
  1270. X    }
  1271. X
  1272. X    if (mf->mf_opts)
  1273. X        opts = mf->mf_opts;
  1274. X    else
  1275. X        opts = "";
  1276. X
  1277. X    opts = strdup(opts);
  1278. X
  1279. X#ifdef DEBUG
  1280. X    dlog("searching for /defaults entry");
  1281. X#endif
  1282. X    if (mapc_search((mnt_map*) mf->mf_private, "/defaults", &dflts) == 0) {
  1283. X          char *dfl;
  1284. X        char **rvec;
  1285. X#ifdef DEBUG
  1286. X        dlog("/defaults gave %s", dflts);
  1287. X#endif
  1288. X        if (*dflts == '-')
  1289. X            dfl = dflts+1;
  1290. X        else
  1291. X            dfl = dflts;
  1292. X
  1293. X        /*
  1294. X         * Chop the defaults up
  1295. X         */
  1296. X        rvec = strsplit(dfl, '\"');
  1297. X        /*
  1298. X         * Extract first value
  1299. X         */
  1300. X        dfl = rvec[0];
  1301. X
  1302. X        /*
  1303. X         * Log error if there were other values
  1304. X         */
  1305. X        if (rvec[1]) {
  1306. X#ifdef DEBUG
  1307. X            dlog("/defaults chopped into %s", dfl);
  1308. X#endif
  1309. X            plog(XLOG_USER, "More than a single value for /defaults in %s", mf->mf_info);
  1310. X        }
  1311. X
  1312. X        /*
  1313. X         * Don't need info vector any more
  1314. X         */
  1315. X        free((voidp) rvec);
  1316. X
  1317. X        /*
  1318. X         * If there were any values at all...
  1319. X         */
  1320. X        if (dfl) {
  1321. X            /*
  1322. X             * Prepend to existing defaults if they exist,
  1323. X             * otherwise just use these defaults.
  1324. X             */
  1325. X            if (*opts && *dfl) {
  1326. X                char *nopts = (char *) xmalloc(strlen(opts)+strlen(dfl)+2);
  1327. X                sprintf(nopts, "%s;%s", dfl, opts);
  1328. X                free(opts);
  1329. X                opts = nopts;
  1330. X            } else if (*dfl) {
  1331. X                opts = strealloc(opts, dfl);
  1332. X            }
  1333. X        }
  1334. X        free(dflts);
  1335. X    }
  1336. X
  1337. X    /*
  1338. X     * Fill it in
  1339. X     */
  1340. X    init_map(new_mp, fname);
  1341. X
  1342. X    /*
  1343. X     * Put it in the table
  1344. X     */
  1345. X    insert_am(new_mp, mp);
  1346. X
  1347. X    /*
  1348. X     * Fill in some other fields,
  1349. X     * path and mount point
  1350. X     */
  1351. X    new_mp->am_path = str3cat(new_mp->am_path, mp->am_path, *fname == '/' ? "" : "/", fname);
  1352. X
  1353. X#ifdef DEBUG
  1354. X    dlog("setting path to %s", new_mp->am_path);
  1355. X#endif
  1356. X
  1357. X    /*
  1358. X     * Take private copy of pfname
  1359. X     */
  1360. X    pfname = strdup(pfname);
  1361. X
  1362. X    /*
  1363. X     * Construct a continuation
  1364. X     */
  1365. X    cp = ALLOC(continuation);
  1366. X    cp->mp = new_mp;
  1367. X    cp->xivec = xivec;
  1368. X    cp->ivec = ivec;
  1369. X    cp->info = info;
  1370. X    cp->key = pfname;
  1371. X    cp->opts = opts;
  1372. X    cp->retry = FALSE;
  1373. X    cp->tried = FALSE;
  1374. X    cp->start = clocktime();
  1375. X    cp->def_opts = strdup(opts);
  1376. X    bzero((voidp) &cp->fs_opts, sizeof(cp->fs_opts));
  1377. X
  1378. X    /*
  1379. X     * Try and mount the file system
  1380. X     * If this succeeds immediately (possible
  1381. X     * for a ufs file system) then return
  1382. X     * the attributes, otherwise just
  1383. X     * return an error.
  1384. X     */
  1385. X    error = afs_bgmount(cp, error);
  1386. X    reschedule_timeout_mp();
  1387. X    if (!error) {
  1388. X        free(fname);
  1389. X        return new_mp;
  1390. X    }
  1391. X
  1392. X    assign_error_mntfs(cp->mp);
  1393. X
  1394. X    free(fname);
  1395. X
  1396. X    ereturn(error);
  1397. X#undef ereturn
  1398. X}
  1399. X
  1400. X/*
  1401. X * Locate next node in sibling list which is mounted
  1402. X * and is not an error node.
  1403. X */
  1404. Xstatic am_node *next_nonerror_node(xp)
  1405. Xam_node *xp;
  1406. X{
  1407. X    mntfs *mf;
  1408. X
  1409. X    /*
  1410. X     * Bug report (7/12/89) from Rein Tollevik <rein@ifi.uio.no>
  1411. X     * Fixes a race condition when mounting direct automounts.
  1412. X     * Also fixes a problem when doing a readdir on a directory
  1413. X     * containing hung automounts.
  1414. X     */
  1415. X    while (xp &&
  1416. X           (!(mf = xp->am_mnt) ||            /* No mounted filesystem */
  1417. X            mf->mf_error != 0 ||            /* There was a mntfs error */
  1418. X            xp->am_error != 0 ||            /* There was a mount error */
  1419. X            !(mf->mf_flags & MFF_MOUNTED) ||    /* The fs is not mounted */
  1420. X            (mf->mf_server->fs_flags & FSF_DOWN))    /* The fs may be down */
  1421. X        )
  1422. X        xp = xp->am_osib;
  1423. X
  1424. X    return xp;
  1425. X}
  1426. X
  1427. Xstatic int afs_readdir(mp, cookie, dp, ep)
  1428. Xam_node *mp;
  1429. Xnfscookie cookie;
  1430. Xstruct dirlist *dp;
  1431. Xstruct entry *ep;
  1432. X{
  1433. X    unsigned int gen = *(unsigned int*) cookie;
  1434. X    am_node *xp;
  1435. X
  1436. X    dp->eof = FALSE;
  1437. X
  1438. X    if (gen == 0) {
  1439. X        /*
  1440. X         * In the default instance (which is used to
  1441. X         * start a search) we return "." and "..".
  1442. X         *
  1443. X         * This assumes that the count is big enough
  1444. X         * to allow both "." and ".." to be returned in
  1445. X         * a single packet.  If it isn't (which would
  1446. X         * be fairly unbelievable) then tough.
  1447. X         */
  1448. X#ifdef DEBUG
  1449. X        dlog("default search");
  1450. X#endif
  1451. X        xp = next_nonerror_node(mp->am_child);
  1452. X        dp->entries = ep;
  1453. X
  1454. X        /* construct "." */
  1455. X        ep[0].fileid = mp->am_gen;
  1456. X        ep[0].name = ".";
  1457. X        ep[0].nextentry = &ep[1];
  1458. X        *(unsigned int *) ep[0].cookie = 0;
  1459. X
  1460. X        /* construct ".." */
  1461. X        if (mp->am_parent)
  1462. X            ep[1].fileid = mp->am_parent->am_gen;
  1463. X        else
  1464. X            ep[1].fileid = mp->am_gen;
  1465. X        ep[1].name = "..";
  1466. X        ep[1].nextentry = 0;
  1467. X        *(unsigned int *) ep[1].cookie =
  1468. X            xp ? xp->am_gen : ~(unsigned int)0;
  1469. X
  1470. X        return 0;
  1471. X    }
  1472. X
  1473. X#ifdef DEBUG
  1474. X    dlog("real child");
  1475. X#endif
  1476. X
  1477. X    if (gen == ~(unsigned int)0) {
  1478. X#ifdef DEBUG
  1479. X        dlog("End of readdir in %s", mp->am_path);
  1480. X#endif
  1481. X        dp->eof = TRUE;
  1482. X        dp->entries = 0;
  1483. X        return 0;
  1484. X    }
  1485. X
  1486. X    xp = mp->am_child;
  1487. X    while (xp && xp->am_gen != gen)
  1488. X        xp = xp->am_osib;
  1489. X
  1490. X    if (xp) {
  1491. X        am_node *xp_next = next_nonerror_node(xp->am_osib);
  1492. X
  1493. X        if (xp_next) {
  1494. X            *(unsigned int *) ep->cookie = xp_next->am_gen;
  1495. X        } else {
  1496. X            *(unsigned int *) ep->cookie = ~(unsigned int)0;
  1497. X        }
  1498. X
  1499. X        ep->fileid = xp->am_gen;
  1500. X        ep->name = xp->am_name;
  1501. X
  1502. X        ep->nextentry = 0;
  1503. X        dp->entries = ep;
  1504. X
  1505. X        return 0;
  1506. X    }
  1507. X
  1508. X    return ESTALE;
  1509. X
  1510. X}
  1511. X
  1512. Xstatic char *dfs_readlink(mp, error_return)
  1513. Xam_node *mp;
  1514. Xint *error_return;
  1515. X{
  1516. X    am_node *xp;
  1517. X    int rc = 0;
  1518. X
  1519. X    xp = next_nonerror_node(mp->am_child);
  1520. X    if (!xp)
  1521. X        xp = afs_lookuppn(mp, mp->am_path+1, &rc, VLOOK_CREATE);
  1522. X
  1523. X    if (xp) {
  1524. X        new_ttl(xp);    /* (7/12/89) from Rein Tollevik */
  1525. X        return xp->am_link ? xp->am_link : xp->am_mnt->mf_mount;
  1526. X    }
  1527. X    if (amd_state == Finishing)
  1528. X        return "/tmp";
  1529. X    *error_return = rc;
  1530. X    return 0;
  1531. X}
  1532. X
  1533. X/*
  1534. X * Ops structure
  1535. X */
  1536. Xam_ops afs_ops = {
  1537. X    MNTTYPE_AUTO,
  1538. X    afs_match,
  1539. X    afs_init,
  1540. X    afs_mount,
  1541. X    afs_umount,
  1542. X    afs_lookuppn,
  1543. X    afs_readdir,
  1544. X    0, /* afs_readlink */
  1545. X    0, /* afs_mounted */
  1546. X    afs_umounted,
  1547. X    find_afs_srvr,
  1548. X    FS_NOTIMEOUT|FS_UBACKGROUND|FS_AMQINFO,
  1549. X    &afs_srvr_list
  1550. X};
  1551. X
  1552. Xam_ops dfs_ops = {
  1553. X    "direct",
  1554. X    afs_match,
  1555. X    0, /* dfs_init */
  1556. X    afs_mount,
  1557. X    afs_umount,
  1558. X    efs_lookuppn,
  1559. X    efs_readdir,
  1560. X    dfs_readlink,
  1561. X    0, /* afs_mounted */
  1562. X    afs_umounted,
  1563. X    find_afs_srvr,
  1564. X    FS_NOTIMEOUT|FS_UBACKGROUND|FS_AMQINFO,
  1565. X    &afs_srvr_list
  1566. X};
  1567. END_OF_FILE
  1568. if test 34481 -ne `wc -c <'afs_ops.c'`; then
  1569.     echo shar: \"'afs_ops.c'\" unpacked with wrong size!
  1570. fi
  1571. # end of 'afs_ops.c'
  1572. fi
  1573. echo shar: End of archive 12 \(of 13\).
  1574. cp /dev/null ark12isdone
  1575. MISSING=""
  1576. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do
  1577.     if test ! -f ark${I}isdone ; then
  1578.     MISSING="${MISSING} ${I}"
  1579.     fi
  1580. done
  1581. if test "${MISSING}" = "" ; then
  1582.     echo You have unpacked all 13 archives.
  1583.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1584. else
  1585.     echo You still need to unpack the following archives:
  1586.     echo "        " ${MISSING}
  1587. fi
  1588. ##  End of shell archive.
  1589. exit 0
  1590. exit 0 # Just in case...
  1591.